﻿using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SignalProcessing
{
    public class Fourier
    {
        public static Dictionary<Double, Double> FourierTransform(Double[] data, Double timeDelta, out Double predominantFrequency, out Double maxAmplitude)
        {
            var output = new Dictionary<Double, Double>();
            predominantFrequency = 0;
            var maxFrequency = (1.0 / timeDelta) / 2.0;

            alglib.complex[] fourier;
            alglib.fftr1d(data, out fourier);
            var dataCount = (int)Math.Floor(fourier.Count() / 2.0);
            maxAmplitude = -Double.MaxValue;
            for (int i = 0; i < dataCount; i++)
            {
                var frequency = i * maxFrequency / dataCount;
                var fourierValue = Math.Abs(fourier[i].x);
                if (frequency > 10 && fourierValue > maxAmplitude)
                {
                    maxAmplitude = fourierValue;
                    predominantFrequency = frequency;
                }

                output.Add(frequency, fourierValue);
            }

            return output;
        }

        private object _lockFourierAverage = new object();
        private ScrollingList<alglib.complex[]> _fourierAverage = new ScrollingList<alglib.complex[]>(10);
        public Dictionary<Double, Double> FourierTransformAveraged(Double[] data, Double timeDelta, int count, out Double predominantFrequency, out Double maxAmplitude)
        {
            if (_fourierAverage.MaxCount != count)
                _fourierAverage.MaxCount = count;

            alglib.complex[] fourier;
            alglib.fftr1d(data, out fourier);

            lock (_lockFourierAverage)
            {
                _fourierAverage.AddItem(fourier);

                if (_fourierAverage.Count < count)
                {
                    predominantFrequency = -1;
                    maxAmplitude = -1;
                    return null;
                }

                var output = new Dictionary<Double, Double>();
                predominantFrequency = 0;
                var maxFrequency = (1.0 / timeDelta) / 2.0;
                var dataCount = (int)Math.Floor(fourier.Count() / 2.0);
                maxAmplitude = -Double.MaxValue;

                for (int pointIndex = 0; pointIndex < _fourierAverage[0].Count(); pointIndex++)
                {
                    var average = 0.0;
                    for (int fourierAverageIndex = 0; fourierAverageIndex < _fourierAverage.Count; fourierAverageIndex++)
                    {

                        average += Math.Abs(_fourierAverage[fourierAverageIndex][pointIndex].x);
                    }

                    var frequency = pointIndex * maxFrequency / dataCount;
                    if (frequency > 20 && frequency < maxFrequency && average > maxAmplitude)
                    {
                        maxAmplitude = average;
                        predominantFrequency = frequency;
                    }

                    output.Add(frequency, average);
                }

                return output;
            }
        }
    }
}
